#ifndef XGE_XSTL_ALLOCATOR_H_
#define XGE_XSTL_ALLOCATOR_H_
#include "xge_common_config.h"
#include "xallocator.h"
#include <limits>
#include <memory>
namespace xge{
namespace xge_internal {

  // Base STL allocator class.
  // base class for generic allocators
  template<typename T>
  struct STLAllocatorBase {	
    typedef T value_type;
  };

  // Base STL allocator class. (const T version).
  // base class for generic allocators for const T
  template<typename T>
  struct STLAllocatorBase<const T> {	
    typedef T value_type;
  };

  template < typename T > 
  class STLAllocator : public STLAllocatorBase<T> {
  public :
    /// define our types, as per ISO C++
    typedef STLAllocatorBase<T>			Base;
    typedef typename Base::value_type	value_type;
    typedef value_type*					pointer;
    typedef const value_type*			const_pointer;
    typedef value_type&					reference;
    typedef const value_type&			const_reference;
    typedef std::size_t					size_type;
    typedef std::ptrdiff_t				difference_type;


    /// the standard rebind mechanism
    template<typename U>
    struct rebind {
      typedef STLAllocator<U> other;
    };

    /// ctor
    inline explicit STLAllocator()
    { }

    /// dtor
    virtual ~STLAllocator()
    { }

    /// copy ctor - done component wise
    inline STLAllocator( STLAllocator const& )
    { }

    /// cast
    template <typename U>
    inline STLAllocator( STLAllocator<U> const& )
    { }

    /// memory allocation (elements, used by STL)
    inline pointer allocate( size_type count,
      typename std::allocator<void>::const_pointer ptr = NULL ) {
      (void)ptr;
      // convert request to bytes
      register size_type sz = count*sizeof( T );
      pointer p  = static_cast<pointer>( XMalloc(sz) );
      return p;
    }

    /// memory deallocation (elements, used by STL)
    inline void deallocate( pointer ptr, size_type ) {
      // convert request to bytes, but we can't use this?
      // register size_type sz = count*sizeof( T );
      XFree(ptr);
    }

    pointer address(reference x) const {
      return &x;
    }

    const_pointer address(const_reference x) const {
      return &x;
    }

    size_type max_size() const throw() {
      // maximum size this can handle, delegate
      return (size_t)(std::numeric_limits<int>::max)();
    }

    void construct(pointer p, const T& val) {
      // call placement new
      new(static_cast<void*>(p)) T(val);
    }

    void destroy(pointer p) {
      // do we have to protect against non-classes here?
      // some articles suggest yes, some no
      p->~T();
    }

  };

  /// determine equality, can memory from another allocator
  /// be released by this allocator, (ISO C++)
  template<typename T, typename T2>
  inline bool operator==(STLAllocator<T> const&,
    STLAllocator<T2> const&) {
    // same alloc policy (P), memory can be freed
    return true;
  }

  /// determine equality, can memory from another allocator
  /// be released by this allocator, (ISO C++)
  template<typename T,typename OtherAllocator>
  inline bool operator==(STLAllocator<T> const&,
    OtherAllocator const&)
  {
    return false;
  }
  /// determine equality, can memory from another allocator
  /// be released by this allocator, (ISO C++)
  template<typename T, typename T2>
  inline bool operator!=(STLAllocator<T> const&,
    STLAllocator<T2> const&)
  {
    // same alloc policy (P), memory can be freed
    return false;
  }

  /// determine equality, can memory from another allocator
  /// be released by this allocator, (ISO C++)
  template<typename T,typename OtherAllocator>
  inline bool operator!=(STLAllocator<T> const&,
    OtherAllocator const&)
  {
    return true;
  }
}

}


#endif// XGE_XSTL_ALLOCATOR_H_